package com.hyt.it.ogt.kq.service.bm.service.impl;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;

import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.alibaba.fastjson15.JSON;
import com.alibaba.fastjson15.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.hyt.core.base.BaseServiceImpl;
import com.hyt.core.enums.DelFlagEnum;
import com.hyt.core.util.DateUtils;
import com.hyt.core.util.FastJsonUtil;
import com.hyt.core.util.UUIDUtils;
import com.hyt.it.ogt.cj.enums.ComponentNameEnum;
import com.hyt.it.ogt.cj.service.IProjectCollectInfoService;
import com.hyt.it.ogt.kq.common.bm.enums.BmCostType;
import com.hyt.it.ogt.kq.common.bm.enums.BmMidOrderPayRefundStatus;
import com.hyt.it.ogt.kq.common.bm.enums.BmMidOrderPayStatus;
import com.hyt.it.ogt.kq.common.bm.enums.BmPayBusinessFlowType;
import com.hyt.it.ogt.kq.common.bm.enums.BmPayStatusEnum;
import com.hyt.it.ogt.kq.common.bm.enums.BmProjectAllowRefundEnum;
import com.hyt.it.ogt.kq.common.bm.enums.BmRefundAuditType;
import com.hyt.it.ogt.kq.common.bm.enums.BmRefundStatusEnum;
import com.hyt.it.ogt.kq.common.bm.enums.pay.PayProviderType;
import com.hyt.it.ogt.kq.common.bm.utils.Constant;
import com.hyt.it.ogt.kq.common.bm.utils.UniqueIDUtils;
import com.hyt.it.ogt.kq.common.config.ConfigManager;
import com.hyt.it.ogt.kq.service.bm.feign.tps.TpsClient;
import com.hyt.it.ogt.kq.service.bm.mapper.OrderBusinessFlowMapper;
import com.hyt.it.ogt.kq.service.bm.mapper.OrderMapper;
import com.hyt.it.ogt.kq.service.bm.mapper.ProjectMapper;
import com.hyt.it.ogt.kq.service.bm.mapper.StudentProjectMapper;
import com.hyt.it.ogt.kq.service.bm.mapper.StudentSubjectMapper;
import com.hyt.it.ogt.kq.service.bm.mapper.StudentSubjectMidOrderDetailsMapper;
import com.hyt.it.ogt.kq.service.bm.model.dto.StudentSubjectDto;
import com.hyt.it.ogt.kq.service.bm.model.dto.pay.RefundQueryQueryRefundResponseDTOResult;
import com.hyt.it.ogt.kq.service.bm.model.entity.Order;
import com.hyt.it.ogt.kq.service.bm.model.entity.OrderBusinessFlow;
import com.hyt.it.ogt.kq.service.bm.model.entity.OrderListVo;
import com.hyt.it.ogt.kq.service.bm.model.entity.Project;
import com.hyt.it.ogt.kq.service.bm.model.entity.ProjectSubject;
import com.hyt.it.ogt.kq.service.bm.model.entity.RefundInfo;
import com.hyt.it.ogt.kq.service.bm.model.entity.StudentProject;
import com.hyt.it.ogt.kq.service.bm.model.entity.StudentSubject;
import com.hyt.it.ogt.kq.service.bm.model.entity.StudentSubjectMidOrderDetails;
import com.hyt.it.ogt.kq.service.bm.model.param.PayOrderListOrderParam;
import com.hyt.it.ogt.kq.service.bm.model.param.PayOrderRefundOrderListParam;
import com.hyt.it.ogt.kq.service.bm.model.vo.OrderInfoVo;
import com.hyt.it.ogt.kq.service.bm.model.vo.OrderParam;
import com.hyt.it.ogt.kq.service.bm.model.vo.PayOrderProject;
import com.hyt.it.ogt.kq.service.bm.model.vo.ProjectOrderFlowVo;
import com.hyt.it.ogt.kq.service.bm.model.vo.Reconciliation;
import com.hyt.it.ogt.kq.service.bm.model.vo.ReconciliationList;
import com.hyt.it.ogt.kq.service.bm.model.vo.RefundComments;
import com.hyt.it.ogt.kq.service.bm.model.vo.RefundTaskList;
import com.hyt.it.ogt.kq.service.bm.model.vo.StudentSubjectVo;
import com.hyt.it.ogt.kq.service.bm.service.IPayOrderService;
import com.hyt.it.ogt.kq.service.bm.service.IProjectService;
import com.hyt.it.ogt.kq.service.bm.service.IProjectSubjectService;
import com.hyt.it.ogt.kq.service.bm.service.IStudentProjectService;
import com.hyt.loginfo.util.OfficeIdToNameUtil;
import com.hyt.loginfo.util.UserIdToNameUtil;
import com.hyt.model.PageParam;
import com.hyt.model.tps.vo.Analysis;
import com.hyt.model.tps.vo.RefundVo;
import com.hyt.util.JsonUtil;
import com.upay.sdk.FastJsonUtils;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.text.CharSequenceUtil;
import cn.hutool.core.util.StrUtil;
import lombok.extern.slf4j.Slf4j;

@Service
@Slf4j
public class PayOrderServiceImpl extends BaseServiceImpl<OrderMapper, Order> implements IPayOrderService {

    @Autowired
    private OrderMapper orderMapper;
    @Resource
    TpsClient tpsClient;
    @Autowired
    private ProjectMapper projectMapper;
    @Autowired
    private StudentSubjectMapper studentSubjectMapper;
    @Autowired
    private StudentProjectMapper studentProjectMapper;
    @Autowired
    private RefundComments refund;
    @Autowired
    protected UserIdToNameUtil<OrderListVo> userIdToNameUtil;
    @Autowired
    private IProjectService iProjectService;
    @Autowired
    protected OfficeIdToNameUtil<Reconciliation> officeIdToNameUtil;
    @Autowired
    private OrderBusinessFlowMapper orderBusinessFlowMapper;
    @Autowired
    private IProjectSubjectService iProjectSubjectService;
    @Resource
    private StudentSubjectMidOrderDetailsMapper studentSubjectMidOrderDetailsMapper;
    @Resource
    ConfigManager configManager;
    @Resource
    IProjectCollectInfoService iProjectCollectInfoService;
    @Resource
    private IStudentProjectService iStudentProjectService;

    @Override
    public IPage<PayOrderProject> queryProjectList(PageParam<PayOrderProject> pageParam, OrderParam param,
                                                   String officeId) {
        return orderMapper.queryProjectList(pageParam, param, officeId);
    }

    @Override
    public IPage<OrderListVo> querylistOrder(PayOrderListOrderParam pageParam) {
        // 如果没有机构采集信息则不设置机构权限查询
        Boolean hasOfficePermission = iProjectCollectInfoService.isComponentRequired(pageParam.getProjectId(), ComponentNameEnum.office.getCode());
        if (!hasOfficePermission) {
            pageParam.setDeptIds(null);
        }
        
        IPage<OrderListVo> page = orderMapper.querylistOrder(pageParam);
        // 替换用户名
        userIdToNameUtil.change(page.getRecords(), OrderListVo::getUserName, OrderListVo::setUserName);
        for (OrderListVo vo : page.getRecords()) {
            // 团体缴费
            if ("1".equals(vo.getIsGroup())) {
                vo.setUserName(orderMapper.getUserNameList(vo.getOrderId()));
            }
            if (vo.getRefundStatus() == 0 || vo.getRefundStatus() == 1 || vo.getRefundStatus() == 2
                    || vo.getRefundStatus() == 4) {
                // 展示退款内容
                vo.setRefundInfo(orderMapper.refundSubjectListDetailNameList(vo.getOrderId()));
            }
        }
        return page;
    }

    @Override
    public IPage<OrderListVo> refundOrderList(PayOrderRefundOrderListParam pageParam) {
        // 如果没有机构采集信息则不设置机构权限查询
        Boolean hasOfficePermission = iProjectCollectInfoService.isComponentRequired(pageParam.getProjectId(), ComponentNameEnum.office.getCode());
        if (!hasOfficePermission) {
            pageParam.setDeptIds(null);
        }

        IPage<OrderListVo> page = orderMapper.refundOrderList(pageParam);
        // 替换用户名
        userIdToNameUtil.change(page.getRecords(), OrderListVo::getUserName, OrderListVo::setUserName);
        List<OrderListVo> listVos = page.getRecords();
        for (OrderListVo vo : listVos) {
            // 团体缴费
            if ("1".equals(vo.getIsGroup())) {
                vo.setUserName(orderMapper.getUserNameList(vo.getOrderId()));
            }
            if (vo.getRefundStatus() == 0 || vo.getRefundStatus() == 1 || vo.getRefundStatus() == 2
                    || vo.getRefundStatus() == 4) {
                // 展示退款内容
                vo.setRefundInfo(orderMapper.refundSubjectListDetailNameList(vo.getOrderId()));
            }
        }
        return page;
    }

    /**
     * 管理端退款
     *
     * @throws Exception
     */
    @Override
    @Transactional
    public boolean refundManage(String orderId, String subjectIds) {
        // 查询订单报名的科目
        Order order = orderMapper.selectById(orderId);
        if (null == order) {
            return false;
        }
        // 如果不存在需要退款的科目，则不受理业务
        List<Integer> refundStatus = new ArrayList<>();
        refundStatus.add(BmMidOrderPayRefundStatus.REFUND_DEFAULT.getRefundStatus());
        List<StudentSubject> refundStudentSubject = orderMapper.refundSubjectList(orderId, refundStatus);
        if (CollectionUtils.isEmpty(refundStudentSubject)) {
            return false;
        }
        String projectId = order.getBmProjectId();
        // 计算退费的总金额
        List<String> refundStudentSubjectIds = new ArrayList<String>();
        String[] refundSubjects = subjectIds.split(",");
        BigDecimal refundAmount = new BigDecimal("0.00");
        for (String refundSubject : refundSubjects) {
            for (StudentSubject studentSubject : refundStudentSubject) {
                if (refundSubject.equals(studentSubject.getSubjectId())) {
                    refundStudentSubjectIds.add(refundSubject);
                    refundAmount = refundAmount.add(BigDecimal.valueOf(studentSubject.getPrice()));
                }
            }
        }
        RefundInfo refundInfo = new RefundInfo();
        refundInfo.setBmOrderId(orderId);
        refundInfo.setRegId("");
        refundInfo.setRefundStudentSubjectid(subjectIds);
        refundInfo.setBmProjectId(projectId);
        refundInfo.setUserName("");
        String refundId = UUIDUtils.newSortUUID();
        refundInfo.setId(refundId);
        // 退款状态（0:退款申请中 ,1：退款中,2：退款完成,3：退款失败，）
        refundInfo.setRefundStatus(BmRefundStatusEnum.REFUND_RUNNING.getRefundStatu());
        refundInfo.setRefundAmount(refundAmount.doubleValue());
        refundInfo.setCreateDate(LocalDateTime.now());
        refundInfo.setUpdateDate(LocalDateTime.now());
        refundInfo.setDelFlag(true);
        RefundComments refundComments = new RefundComments();
        refundComments.setId(refundId);
        // 同意退款
        Project project = projectMapper.selectById(projectId);
        // 申请去第三方退款
        Map<String, Object> map = new HashMap<String, Object>();
        // 从订单支付回调表里--获取交易流水号
        String serialNumber = orderMapper.getSerialNumber(orderId);
        // 回调地址
        String notifyCallBackUrl = getPayRefundNotifyUrl(refundComments, project, refund.getIp(), refund.getPort());
        RefundVo queryVo = new RefundVo();
        queryVo.setOfficeId(project.getOfficeId());
        queryVo.setOrderId(orderId);
        queryVo.setRefundOrderPrice(refundAmount.doubleValue());
        queryVo.setNotifyUrl(notifyCallBackUrl);
        queryVo.setSerialNumber(serialNumber);
        try {
            log.info("## refundManage queryVo:{}", FastJsonUtil.getBeanToJson(queryVo));
            map = (Map<String, Object>) tpsClient.refund(queryVo);
            log.info("## refundManage map:{}", FastJsonUtil.getBeanToJson(map));
        } catch (Exception e) {
            log.error("***************第三方调用异常===========", e);
            return false;
        }
        // 更新 订单报名科目明细表 （退款申请状态，默认：0，申请退款中：1）
        orderMapper.updateSubjectMidOrderRefundStatus(orderId, refundStudentSubjectIds, BmMidOrderPayRefundStatus.REFUND_PEDDING.getRefundStatus());
        // 首先将之前的退款记录软删除 is_delete_flag设置为1
        orderMapper.updateRefundDeleteFlag(orderId);
        // 申请退款-保存申请退款表
        orderMapper.insertRefund(refundInfo);
        // 获取退款交易流水号
        Map<String, Object> jsonObject = (Map<String, Object>) map.get("obj");
        String refundSerialNumber = "";
        // 退款成功
        if ("0".equals(map.get("code"))) {
            // 更新退款记录表 退款中
            refundSerialNumber = (String) jsonObject.get("serialNumber");
            refundComments.setSerialNumber(refundSerialNumber);
            refundComments.setRefundStatus(1);// 退款状态（0:退款申请中 ,1：退款中,2：退款完成,3：退款失败，）
            orderMapper.updateRefund(refundComments);
            // 新增业务流水表
            addBusinessFlow(order, refundStudentSubjectIds, BmPayBusinessFlowType.REFUND_PEDDING.getBusinessType());
        } else if ("-1".equals(map.get("code"))) {
            /// 易宝支付直接退款，没有回调
            refundSerialNumber = (String) jsonObject.get("serialNumber");
            String amount = (String) jsonObject.get("r3_Amt");
            //判断是否是部分退款
            Double doubleAmount = Double.parseDouble(amount);
            // 通过订单号查询订单详情
            refundComments.setSerialNumber(refundSerialNumber);
            // 订单金额大于退款金额
            if (order.getOrderPrice() > doubleAmount) {
                refundComments.setRefundStatus(BmRefundStatusEnum.REFUND_PART_SUCCESS.getRefundStatu());// 部分退款
            } else {
                refundComments.setRefundStatus(BmRefundStatusEnum.REFUND_SUCCESS.getRefundStatu());// 退款成功
            }
            refundComments.setUpdateDate(LocalDateTime.now());
            // 更新订单退款表 bm_order_refund
            orderMapper.updateRefund(refundComments);


            // 查询退款申请中的科目
            List<StudentSubject> subjectList = studentSubjectMapper.getStuSubjectsByOrderIdAndSubjectIds(orderId, refundStudentSubjectIds);
            log.info("## refundManage subjectList:{}", FastJsonUtil.getBeanToJson(subjectList));

            for (StudentSubject studentSubject : subjectList) {
                studentSubject.setPay(6);// 缴费退款
                studentSubject.setUpdateDate(LocalDateTime.now());
                // 更新报名科目状态
                studentSubjectMapper.updateById(studentSubject);
            }

            // 更新中间表的退款状态为退款成功
            List<String> list = new ArrayList<String>();
            if (CollectionUtils.isNotEmpty(subjectList)) {
                for (StudentSubject studentSubject : subjectList) {
                    list.add(studentSubject.getId());
                }
                // 更新 订单报名科目明细表 （退款申请状态，默认：0，申请退款中：1）
                orderMapper.updateSubjectMidOrderRefundStatus(orderId, list, BmMidOrderPayRefundStatus.REFUND_SUCCESS.getRefundStatus());
            }

            // 如果订单的所有的科目都退款完成，则需要修改退款订单的状态的退款完成
            List<StudentSubjectMidOrderDetails> subjectMidOrderDetails = studentSubjectMidOrderDetailsMapper.queryUnRefundFinishSubjects(orderId, BmMidOrderPayRefundStatus.REFUND_SUCCESS.getRefundStatus());
            log.info("## refundManage subjectMidOrderDetails:{}", FastJsonUtil.getBeanToJson(subjectMidOrderDetails));
            // 没有查到为退款完成的，说明全部退款完成
            if (CollUtil.isEmpty(subjectMidOrderDetails)) {
                // 修改退款订单状态为退款完成
                orderMapper.updateRefundStatus(orderId, null, BmRefundStatusEnum.REFUND_SUCCESS.getRefundStatu());
            }

            // 管理端退款直接新增流水
            addBusinessFlow(order, refundStudentSubjectIds, BmPayBusinessFlowType.REFUND_SUCCESS.getBusinessType());

            Map<String, List<String>> subjectStudents = new HashMap<>();
            if (CollectionUtils.isNotEmpty(subjectList)) {
                //对科目的考生进行分组
                for (StudentSubject studentSubject : subjectList) {
                    String subjectId = studentSubject.getSubjectId();
                    if (subjectStudents.containsKey(subjectId)) {
                        List<String> studentIds = subjectStudents.get(subjectId);
                        studentIds.add(studentSubject.getStudentId());
                    } else {
                        List<String> studentIds = new ArrayList<>();
                        studentIds.add(studentSubject.getStudentId());
                        subjectStudents.put(subjectId, studentIds);
                    }
                }
            }
            log.info("## refundNotifyUrl subjectStudents:{}", FastJsonUtil.getBeanToJson(subjectStudents));
        } else {
            // 退款失败-直接返回原因
            refundComments.setResult((String) map.get("msg"));
            refundComments.setRefundStatus(3);// 退款状态（0:退款申请中 ,1：退款中,2：退款完成,3：退款失败，）
            orderMapper.updateRefund(refundComments);
            // 新增业务流水表
            addBusinessFlow(order, refundStudentSubjectIds, BmPayBusinessFlowType.REFUND_FAIL.getBusinessType());
        }
        return true;
    }

    private void addBusinessFlow(Order order, List<String> refundStudentSubjectIds, String businessFlowType) {
        String orderId = order.getId();
        for (String refundStudentSubjectId : refundStudentSubjectIds) {
            StudentSubject studentSubject = studentSubjectMapper.getStudentSubjectById(refundStudentSubjectId);
            if (null != studentSubject) {
                ProjectSubject projectSubject = iProjectSubjectService.queryBySubjectId(studentSubject.getProjectId(), studentSubject.getSubjectId());
                if (null != projectSubject) {
                    String orderDetailsId = orderMapper.getOrderDetailId(orderId);
                    OrderBusinessFlow orderBusinessFlow = new OrderBusinessFlow();
                    Long businessFlowId = UniqueIDUtils.generateId();
                    orderBusinessFlow.setId(businessFlowId);
                    orderBusinessFlow.setBmOrderId(orderId);
                    orderBusinessFlow.setBmOrderDetailId(orderDetailsId);
                    orderBusinessFlow.setBusinessType(BmCostType.COST_BM.getType());
                    orderBusinessFlow.setBusinessStatus(businessFlowType);
                    if (null != projectSubject && null != projectSubject.getPrice()) {
                        orderBusinessFlow.setOrderPrice(Double.valueOf(String.valueOf(projectSubject.getPrice())));
                    }
                    orderBusinessFlow.setOrderPaySupplier(order.getOrderPaySupplier());
                    orderBusinessFlow.setOrderType(order.getOrderType());
                    orderBusinessFlow.setBmProjectId(order.getBmProjectId());
                    orderBusinessFlow.setRegId(order.getRegId());
                    orderBusinessFlow.setBmStudentSubjectId(refundStudentSubjectId);
                    orderBusinessFlow.setStudentId(studentSubject.getStudentId());
                    orderBusinessFlow.setCreateDate(LocalDateTime.now());
                    orderBusinessFlow.setUpdateDate(LocalDateTime.now());
                    orderBusinessFlow.setDelFlag(Boolean.FALSE);
                    orderBusinessFlowMapper.insert(orderBusinessFlow);
                }
            }
        }
    }

    @Override
    public OrderInfoVo queryOrderInfo(String orderId) {

        OrderInfoVo orderInfoVo = orderMapper.queryOrderInfo(orderId);
        String bmProjectId = orderInfoVo.getProjectId();
        Project project = iProjectService.getById(bmProjectId);
        // 计算当前是否允许退款
        if (null != project) {
            // 首先看项目是否允许退款,如果不允许退款，直接不如许
            if (project.getIsRefund().equals(1)) {
                orderInfoVo.setAllowRefund(Boolean.FALSE);
            }
            // 如果允许退款，查看是否已经过了退款时间
            LocalDateTime refuseTime = project.getRefuseTime();
            if (null != refuseTime && refuseTime.isBefore(LocalDateTime.now())) {
                orderInfoVo.setAllowRefund(Boolean.FALSE);
            }
        }

        // 团体
        if ("1".equals(orderInfoVo.getIsGroup())) {
            orderInfoVo.setStudentName("团体");
            // 查询用户名
            orderInfoVo.setPayName(userIdToNameUtil.getName(orderInfoVo.getRegId()));
        } else {
            // 通过regID和项目id查询考生姓名、电话
            String name = orderMapper.getStudentValueById("name", orderInfoVo.getRegId(), orderInfoVo.getProjectId());
            String phone = orderMapper.getStudentValueById("phone", orderInfoVo.getRegId(), orderInfoVo.getProjectId());
            orderInfoVo.setStudentName(name);
            orderInfoVo.setPayName(userIdToNameUtil.getName(orderInfoVo.getRegId()));
            orderInfoVo.setStudentPhone(phone);
        }

        // 获取报名科目列表
        List<StudentSubjectVo> list = orderMapper.getStuSubjectListById(orderId);
        orderInfoVo.setOrderInfo(list);
        return orderInfoVo;
    }

    @Override
    public List<StudentSubject> refundSubjectList(String orderId) {
        List<Integer> refundStatus = new ArrayList<>();
        refundStatus.add(BmMidOrderPayRefundStatus.REFUND_DEFAULT.getRefundStatus());
        refundStatus.add(BmMidOrderPayRefundStatus.REFUND_FAIL.getRefundStatus());
        return orderMapper.refundSubjectList(orderId, refundStatus);
    }


    @Override
    public List<StudentSubjectVo> queryRefundSubjectListByProjectId(String projectId, String studentId) {
        // 校验项目是不是存在
        Project projectInfo = projectMapper.selectById(projectId);
        if (null == projectInfo) {
            return null;
        }
        // 查询项目考生是不是存在
        StudentProject studentProject = studentProjectMapper.selectById(studentId);
        if (null == studentProject) {
            return null;
        }
        List<StudentSubjectVo> studentSubjectVos = new ArrayList<StudentSubjectVo>();
        List<StudentSubjectDto> studentSubjectDtos = orderMapper.queryRefundSubjectsByProjectId(projectId, studentId, null, BmMidOrderPayStatus.PAY_SUCCESS.getPayStatus(),
                BmMidOrderPayRefundStatus.REFUND_DEFAULT.getRefundStatus());
        if (CollectionUtils.isNotEmpty(studentSubjectDtos)) {
            for (StudentSubjectDto studentSubjectDto : studentSubjectDtos) {
                StudentSubjectVo studentSubjectVo = new StudentSubjectVo();
                studentSubjectVo.setOrderId(studentSubjectDto.getOrderId());
                studentSubjectVo.setProjcetName(projectInfo.getProjectName());
                studentSubjectVo.setStudentId(studentSubjectDto.getStudentId());
                studentSubjectVo.setSubjectId(studentSubjectDto.getSubjectId());
                studentSubjectVo.setSubjectName(studentSubjectDto.getSubjectName());
                studentSubjectVo.setSubjectPrice(studentSubjectDto.getSubjectPrice());
                studentSubjectVo.setUserName(studentSubjectDto.getUserName());
                studentSubjectVos.add(studentSubjectVo);
            }
        }
        return studentSubjectVos;
    }

    // 退款详情
    @Override
    public List<StudentSubject> refundSubjectListDetail(String orderId) {

        return orderMapper.refundSubjectListDetail(orderId);
    }

    // 退款详情
    @Override
    public List<StudentSubject> refundSubjectListDetail(String orderId, String refundOrderId) {
        List<StudentSubject> qureyResult = new ArrayList<StudentSubject>();
        List<StudentSubject> refundStudentSubjects = orderMapper.refundSubjectListDetail(orderId);
        String refundStudentSubjectIdsStr = orderMapper.getRefundStudentSubjectIdsByRefundOrderId(refundOrderId);
        if (StringUtils.isNotEmpty(refundStudentSubjectIdsStr)) {
            String[] refundStudentSubjectIds = refundStudentSubjectIdsStr.split(",");
            if (null != refundStudentSubjectIds && refundStudentSubjectIds.length > 0) {
                for (StudentSubject studentSubject : refundStudentSubjects) {
                    for (String refundStudentSubjectId : refundStudentSubjectIds) {
                        if (studentSubject.getSubjectId().equals(refundStudentSubjectId)) {
                            qureyResult.add(studentSubject);
                        }
                    }
                }
            }
        }
        return qureyResult;
    }

    /**
     * 考生申请退款
     */
    @Override
    public int applyForRefund(String orderId, String subjectIds, String regId, String projectId) {
        OrderInfoVo orderInfoVo = orderMapper.queryOrderInfo(orderId);
        Object sum = orderMapper.sumOrderRefund(orderId);
        if (null != sum && !((new BigDecimal(sum.toString())).compareTo(orderInfoVo.getActrualPrice()) < 0)) {
            return 31181803;
        }
        // 查询项目并校验是否过了退费时间
        Project project = projectMapper.selectById(projectId);
        if (null != project) {
            if (null != project.getRefuseTime() && project.getRefuseTime().isBefore(LocalDateTime.now())) {
                return 31181802;
            }
        }
        // 通过regID和项目id查询考生姓名
        String userName = orderMapper.getStudentValueById("name", regId, projectId);
        // 主要计算未申请退费的金额
        List<Integer> refundStatus = new ArrayList<>();
        refundStatus.add(BmMidOrderPayRefundStatus.REFUND_DEFAULT.getRefundStatus());
        List<StudentSubject> listSubjects = orderMapper.refundSubjectList(orderId, refundStatus);
        // 主要计算未申请退费的金额
        List<StudentSubject> flowSubjects = new ArrayList<StudentSubject>();
        List<String> refundStudentSubjectIds = new ArrayList<String>();
        String[] refundSubjects = subjectIds.split(",");
        // 计算退款金额
        Double refundAmount = 0.00;
        for (String refundSubject : refundSubjects) {
            for (StudentSubject studentSubject : listSubjects) {
                if (refundSubject.equals(studentSubject.getSubjectId())) {
                    refundStudentSubjectIds.add(refundSubject);
                    refundAmount += studentSubject.getPrice();
                    flowSubjects.add(studentSubject);
                }
            }
        }
        // 如果订单下面不存在需要退款的科目
        if (CollectionUtils.isEmpty(refundStudentSubjectIds)) {
            return 31181801;
        }

        RefundInfo refundInfo = new RefundInfo();
        refundInfo.setBmOrderId(orderId);
        refundInfo.setRegId(regId);
        refundInfo.setBmProjectId(projectId);
        refundInfo.setRefundStudentSubjectid(String.join(",", refundStudentSubjectIds));
        refundInfo.setUserName(userName);
        refundInfo.setId(UUIDUtils.newSortUUID());
        // 退款状态（0:退款申请中 ,1：退款中,2：退款完成,3：退款失败，）
        refundInfo.setRefundStatus(BmRefundStatusEnum.REFUND_APPLY.getRefundStatu());
        refundInfo.setRefundAmount(refundAmount);
        refundInfo.setCreateDate(LocalDateTime.now());
        refundInfo.setUpdateDate(LocalDateTime.now());
        refundInfo.setDelFlag(true);
        // 首先将之前的退款记录软删除 is_delete_flag设置为1
        orderMapper.updateRefundDeleteFlag(orderId);
        // 申请退款-保存申请退款表
        orderMapper.insertRefund(refundInfo);
        // 更新 订单报名科目明细表 （退款申请状态，默认：0，申请退款中：1）
        orderMapper.updateSubjectMidOrderRefundStatus(orderId, refundStudentSubjectIds, BmMidOrderPayRefundStatus.REFUND_APPLY.getRefundStatus());

        // 更新业务流水表
        Order order = orderMapper.selectById(orderId);

        addBusinessFlow(order, refundStudentSubjectIds, BmPayBusinessFlowType.REFUND_APPLY.getBusinessType());

        return Constant.RESPONSE_CODE_SUCCESS;
    }


    /**
     * 考生按照科目进行退款申请
     */
    @Override
    public int applyForRefundBySubjects(String callRefundsubjectsStr, String regId, String projectId) {
        // 首先获取该考生缴费的科目
        Project projectInfo = projectMapper.selectById(projectId);
        if (null == projectInfo) {
            return 0;
        }
        // 查询项目并校验是否过了退费时间
        Project project = projectMapper.selectById(projectId);
        if (null != project) {
            if (null != project.getRefuseTime() && project.getRefuseTime().isBefore(LocalDateTime.now())) {
                return 31181802;
            }
            // 查询项目是否允许退费
            if (null != project.getIsRefund() && BmProjectAllowRefundEnum.UNALLOW.getRefundStatus().equals(project.getIsRefund())) {
                return 31181804;
            }
        }
        // 查询项目考生是不是存在
        StudentProject studentProject = studentProjectMapper.getProjectStudent(projectId, regId);
        if (null == studentProject) {
            return 0;
        }
        if (StringUtils.isEmpty(callRefundsubjectsStr)) {
            return 0;
        }
        // 客户操作的退款科目
        List<String> callRefundsubjects = Arrays.asList(callRefundsubjectsStr.split(","));
        // 获取退款的订单map数据
        Map<String, List<StudentSubjectVo>> orderMapSubjectsMap = getRefundOrderMap(projectId, projectInfo, studentProject, callRefundsubjects);

        if (MapUtil.isNotEmpty(orderMapSubjectsMap)) {
            for (String orderId : orderMapSubjectsMap.keySet()) {
                List<StudentSubjectVo> studentSubjectVos = orderMapSubjectsMap.get(orderId);

                OrderInfoVo orderInfoVo = orderMapper.queryOrderInfo(orderId);
                Object sum = orderMapper.sumOrderRefund(orderId);
                if (null != sum && !((new BigDecimal(sum.toString())).compareTo(orderInfoVo.getActrualPrice()) < 0)) {
                    return 31181803;
                }
                // 通过regID和项目id查询考生姓名
                String userName = orderMapper.getStudentValueById("name", regId, projectId);
                // 主要计算未申请退费的金额
                List<String> refundStudentSubjectIds = new ArrayList<String>();
                // 计算退款金额
                Double refundAmount = 0.00;
                for (StudentSubjectVo studentSubjectVo : studentSubjectVos) {
                    refundAmount += Double.valueOf(studentSubjectVo.getSubjectPrice());
                    refundStudentSubjectIds.add(studentSubjectVo.getSubjectId());
                }

                RefundInfo refundInfo = new RefundInfo();
                refundInfo.setBmOrderId(orderId);
                refundInfo.setRegId(regId);
                refundInfo.setBmProjectId(projectId);
                refundInfo.setRefundStudentSubjectid(String.join(",", refundStudentSubjectIds));
                refundInfo.setUserName(userName);
                refundInfo.setId(UUIDUtils.newSortUUID());
                // 退款状态（0:退款申请中 ,1：退款中,2：退款完成,3：退款失败，）
                refundInfo.setRefundStatus(BmRefundStatusEnum.REFUND_APPLY.getRefundStatu());
                refundInfo.setRefundAmount(refundAmount);
                refundInfo.setCreateDate(LocalDateTime.now());
                refundInfo.setUpdateDate(LocalDateTime.now());
                refundInfo.setDelFlag(true);
                // 首先将之前的退款记录软删除 is_delete_flag设置为1
                orderMapper.updateRefundDeleteFlag(orderId);
                // 申请退款-保存申请退款表
                orderMapper.insertRefund(refundInfo);
                // 更新 订单报名科目明细表 （退款申请状态，默认：0，申请退款中：1）
                orderMapper.updateSubjectMidOrderRefundStatus(orderId, refundStudentSubjectIds, BmMidOrderPayRefundStatus.REFUND_APPLY.getRefundStatus());

                // 更新业务流水表
                Order order = orderMapper.selectById(orderId);

                addBusinessFlow(order, refundStudentSubjectIds, BmPayBusinessFlowType.REFUND_APPLY.getBusinessType());
            }
        } else {
            return 31181811;
        }
        return Constant.RESPONSE_CODE_SUCCESS;
    }

    private Map<String, List<StudentSubjectVo>> getRefundOrderMap(String projectId, Project projectInfo, StudentProject studentProject, List<String> callRefundsubjects) {
        Map<String, List<StudentSubjectVo>> orderMapSubjectsMap = new HashMap<String, List<StudentSubjectVo>>();
        List<StudentSubjectDto> studentSubjectDtos = new ArrayList<StudentSubjectDto>();
        for (String callRefundsubject : callRefundsubjects) {
            // 校验科目有没有申请中的退款中的订单
            List<String> refundSubjectIds = new ArrayList<String>();
            List<RefundInfo> refundInfos = orderMapper.getRefundSubjectListByProjectId(projectId, BmRefundStatusEnum.REFUND_APPLY.getRefundStatu());
            if (CollectionUtils.isNotEmpty(refundInfos)) {
                refundSubjectIds = getProjectRefundSubjectIds(refundInfos);
            }
            // 查询可退款的科目
            List<StudentSubjectDto> studentSubjectDtosTemp = orderMapper.queryRefundSubjectsByProjectId(projectId, null, callRefundsubject, BmMidOrderPayStatus.PAY_SUCCESS.getPayStatus(),
                    BmMidOrderPayRefundStatus.REFUND_DEFAULT.getRefundStatus());
            if (CollectionUtils.isNotEmpty(studentSubjectDtosTemp)) {
                for (StudentSubjectDto studentSubjectDto : studentSubjectDtosTemp) {
                    if (refundSubjectIds.contains(callRefundsubject)) {
                        continue;
                    }
                    studentSubjectDtos.add(studentSubjectDto);
                }
            }
        }

        if (CollectionUtils.isNotEmpty(studentSubjectDtos)) {
            for (StudentSubjectDto studentSubjectDto : studentSubjectDtos) {
                if (!orderMapSubjectsMap.containsKey(studentSubjectDto.getOrderId())) {
                    List<StudentSubjectVo> refundSubject = new ArrayList<StudentSubjectVo>();
                    StudentSubjectVo studentSubjectVo = new StudentSubjectVo();
                    studentSubjectVo.setOrderId(studentSubjectDto.getOrderId());
                    studentSubjectVo.setProjcetName(projectInfo.getProjectName());
                    studentSubjectVo.setStudentId(studentSubjectDto.getStudentId());
                    studentSubjectVo.setSubjectId(studentSubjectDto.getSubjectId());
                    studentSubjectVo.setSubjectName(studentSubjectDto.getSubjectName());
                    studentSubjectVo.setSubjectPrice(studentSubjectDto.getSubjectPrice());
                    studentSubjectVo.setUserName(studentSubjectDto.getUserName());
                    refundSubject.add(studentSubjectVo);
                    orderMapSubjectsMap.put(studentSubjectDto.getOrderId(), refundSubject);
                } else {
                    List<StudentSubjectVo> refundSubject = orderMapSubjectsMap.get(studentSubjectDto.getOrderId());
                    StudentSubjectVo studentSubjectVo = new StudentSubjectVo();
                    studentSubjectVo.setOrderId(studentSubjectDto.getOrderId());
                    studentSubjectVo.setProjcetName(projectInfo.getProjectName());
                    studentSubjectVo.setStudentId(studentSubjectDto.getStudentId());
                    studentSubjectVo.setSubjectId(studentSubjectDto.getSubjectId());
                    studentSubjectVo.setSubjectName(studentSubjectDto.getSubjectName());
                    studentSubjectVo.setSubjectPrice(studentSubjectDto.getSubjectPrice());
                    studentSubjectVo.setUserName(studentSubjectDto.getUserName());
                    refundSubject.add(studentSubjectVo);
                    orderMapSubjectsMap.put(studentSubjectDto.getOrderId(), refundSubject);
                }
            }
        }
        return orderMapSubjectsMap;
    }

    private List<String> getProjectRefundSubjectIds(List<RefundInfo> refundInfos) {
        List<String> refuneSubjectIds = new ArrayList<String>();
        if (CollectionUtils.isEmpty(refundInfos)) {
            return refuneSubjectIds;
        }
        Set<String> refundSubjectIdSet = new HashSet<String>();
        for (RefundInfo refundInfo : refundInfos) {
            String refundSubjectIdTemps = refundInfo.getRefundStudentSubjectid();
            if (StringUtils.isNotEmpty(refundSubjectIdTemps)) {
                String[] ids = refundSubjectIdTemps.split(",");
                if (null != ids && ids.length > 0) {
                    for (int i = 0; i < ids.length; i++) {
                        refundSubjectIdSet.add(refundSubjectIdTemps);
                    }
                }
            }
        }
        if (CollectionUtils.isNotEmpty(refundSubjectIdSet)) {
            Iterator<String> iterator = refundSubjectIdSet.iterator();
            while (iterator.hasNext()) {
                refuneSubjectIds.add(iterator.next());
            }
        }

        return refuneSubjectIds;
    }

    /**
     * 管理端确认-是否退款
     *
     * @throws Exception
     */
    @Override
    public String refundComments(RefundComments refundComments) throws Exception {
        String msg = "";
        String orderId = refundComments.getOrderId();
        // 根据订单查询退费中的科目信息
        List<Integer> refundStatus = new ArrayList<>();
        refundStatus.add(BmMidOrderPayRefundStatus.REFUND_APPLY.getRefundStatus());
        List<StudentSubject> listSubjects = orderMapper.refundSubjectList(orderId, refundStatus);
        // 拒绝退款
        if (BmRefundAuditType.REFUSE.getType().equals(refundComments.getRefundStatus())) {
            List<String> list = new ArrayList<String>();
            if (CollectionUtils.isNotEmpty(listSubjects)) {
                for (StudentSubject subject : listSubjects) {
                    list.add(subject.getSubjectId());
                }
            }
            // 更新退款记录表 --退款失败
            refundComments.setRefundStatus(BmRefundStatusEnum.REFUND_FAIL.getRefundStatu());// 退款状态（0:退款申请中 ,1：退款中,2：退款完成,3：退款失败，）
            orderMapper.updateRefund(refundComments);
            if (CollectionUtils.isNotEmpty(list)) {
                // 更新 订单报名科目明细表 （退款申请状态，默认：0，申请退款中：1）
                orderMapper.updateSubjectMidOrderRefundStatus(orderId, list, BmMidOrderPayRefundStatus.REFUND_DEFAULT.getRefundStatus());
            }
            // 更新业务流水表
            List<String> queryBusinessFlowTypes = new ArrayList<String>();
            queryBusinessFlowTypes.add(BmPayBusinessFlowType.REFUND_APPLY.getBusinessType());
            updateBusinessFlow(orderId, listSubjects, queryBusinessFlowTypes, BmPayBusinessFlowType.REFUND_FAIL.getBusinessType());
            return "14001";
        }
        // 同意退款
        if (BmRefundAuditType.ALLOW.getType().equals(refundComments.getRefundStatus())) {
            Project project = projectMapper.selectById(refundComments.getProjectId());
            // 申请去第三方退款
            Map<String, Object> map = new HashMap<String, Object>();
            // 从订单支付回调表里--获取交易流水号
            String serialNumber = orderMapper.getSerialNumber(orderId);
            // 回调ip和port
            String ip = StringUtils.isNotEmpty(refundComments.getIp()) ? refundComments.getIp() : refund.getIp();
            String port = StringUtils.isNotEmpty(refundComments.getPort()) ? refundComments.getPort() : refund.getPort();
            // 获取退款回调地址
            String refundNotifyCallUrl = getPayRefundNotifyUrl(refundComments, project, ip, port);
            // 获取退费订单中的退款金额
            String refundAmount = orderMapper.getRefundAmountById(refundComments.getId());
            RefundVo queryVo = new RefundVo();
            queryVo.setOfficeId(project.getOfficeId());
            queryVo.setOrderId(orderId);
            queryVo.setRefundOrderPrice(Double.parseDouble(refundAmount));
            queryVo.setNotifyUrl(refundNotifyCallUrl);
            queryVo.setSerialNumber(serialNumber);
            try {
                log.info("## refundComments queryVo:{}", FastJsonUtil.getBeanToJson(queryVo));
                map = (Map<String, Object>) tpsClient.refund(queryVo);
                log.info("## refundComments map:{}", FastJsonUtil.getBeanToJson(map));
            } catch (Exception e) {
                log.info("tpsClient.refund调用异常", e);
            }
            // 获取退款交易流水号
            Map<String, Object> jsonObject = (Map<String, Object>) map.get("obj");
            String refundSerialNumber = "";
            // 退款成功
            if ("0".equals(map.get("code"))) {
                // 更新退款记录表 退款中
                refundSerialNumber = (String) jsonObject.get("serialNumber");
                refundComments.setSerialNumber(refundSerialNumber);
                refundComments.setRefundStatus(BmRefundStatusEnum.REFUND_RUNNING.getRefundStatu());// 退款状态（0:退款申请中,1：退款中,2：退款完成,3：退款失败，）
                orderMapper.updateRefund(refundComments);

                // 更新订单科目中间表
                List<String> list = new ArrayList<String>();
                List<StudentSubject> subjectList = studentSubjectMapper.getStuSubjectsByOrderIdAndOrderRefundStatus(orderId, BmMidOrderPayRefundStatus.REFUND_APPLY.getRefundStatus());
                if (CollectionUtils.isNotEmpty(subjectList)) {
                    for (StudentSubject studentSubject : subjectList) {
                        list.add(studentSubject.getId());
                    }
                    // 更新 订单报名科目明细表 （退款申请状态，默认：0，申请退款中：1）
                    orderMapper.updateSubjectMidOrderRefundStatus(orderId, list, BmMidOrderPayRefundStatus.REFUND_PEDDING.getRefundStatus());
                }

                // 更新流水表
                List<String> queryBusinessFlowTypes = new ArrayList<String>();
                queryBusinessFlowTypes.add(BmPayBusinessFlowType.REFUND_APPLY.getBusinessType());
                updateBusinessFlow(orderId, listSubjects, queryBusinessFlowTypes, BmPayBusinessFlowType.REFUND_PEDDING.getBusinessType());
                msg = "14001";
            } else if ("-1".equals(map.get("code"))) {
                // 易宝支付直接退款，没有回调
                refundSerialNumber = (String) jsonObject.get("serialNumber");
                String amount = (String) jsonObject.get("r3_Amt");
                //判断是否是部分退款
                Double doubleAmount = Double.parseDouble(amount);
                // 通过订单号查询订单详情
                Order order = orderMapper.selectById(orderId);
                refundComments.setSerialNumber(refundSerialNumber);
                // 订单金额大于退款金额
                if (order.getOrderPrice() > doubleAmount) {
                    refundComments.setRefundStatus(BmRefundStatusEnum.REFUND_PART_SUCCESS.getRefundStatu());// 部分退款
                } else {
                    refundComments.setRefundStatus(BmRefundStatusEnum.REFUND_SUCCESS.getRefundStatu());// 退款成功
                }
                refundComments.setUpdateDate(LocalDateTime.now());
                // 更新订单退款表 bm_order_refund
                orderMapper.updateRefund(refundComments);

                // 查询退款申请中的科目
                List<String> list = new ArrayList<>();
                List<StudentSubject> subjectList = studentSubjectMapper.getStuSubjectsByOrderIdAndOrderRefundStatus(orderId, BmMidOrderPayRefundStatus.REFUND_APPLY.getRefundStatus());
                log.info("## refundComments subjectList:{}", FastJsonUtil.getBeanToJson(subjectList));

                if (CollectionUtils.isNotEmpty(subjectList)) {
                    for (StudentSubject studentSubject : subjectList) {
                        list.add(studentSubject.getId());
                        studentSubject.setPay(BmPayStatusEnum.REFUND_SUCEESS.getPayStatus());// 缴费退款
                        studentSubject.setUpdateDate(LocalDateTime.now());
                        // 更新报名科目状态
                        studentSubjectMapper.updateById(studentSubject);
                    }
                    // 更新 订单报名科目明细表 （退款申请状态，默认：0，申请退款中：1）
                    orderMapper.updateSubjectMidOrderRefundStatus(orderId, list, BmMidOrderPayRefundStatus.REFUND_SUCCESS.getRefundStatus());
                    // 更新 订单报名科目明细表 （缴费状态，默认：0，申请退款中：1）
                    //orderMapper.updateSubjectMidOrderPayStatus(orderId, list, BmMidOrderPayStatus.PAY_DETAULT.getPayStatus());
                }

                // 如果订单的所有的科目都退款完成，则需要修改退款订单的状态的退款完成
                List<StudentSubjectMidOrderDetails> subjectMidOrderDetails = studentSubjectMidOrderDetailsMapper.queryUnRefundFinishSubjects(orderId, BmMidOrderPayRefundStatus.REFUND_SUCCESS.getRefundStatus());
                log.info("## refundManage subjectMidOrderDetails:{}", FastJsonUtil.getBeanToJson(subjectMidOrderDetails));
                // 没有查到为退款完成的，说明全部退款完成
                if (CollUtil.isEmpty(subjectMidOrderDetails)) {
                    // 修改退款订单状态为退款完成
                    orderMapper.updateRefundStatus(orderId, null, BmRefundStatusEnum.REFUND_SUCCESS.getRefundStatu());
                }

                // 更新流水表
                List<String> queryBusinessFlowTypes = new ArrayList<String>();
                queryBusinessFlowTypes.add(BmPayBusinessFlowType.REFUND_APPLY.getBusinessType());
                updateBusinessFlow(orderId, listSubjects, queryBusinessFlowTypes, BmPayBusinessFlowType.REFUND_SUCCESS.getBusinessType());


                Map<String, List<String>> subjectStudents = new HashMap<>();
                if (CollectionUtils.isNotEmpty(subjectList)) {
                    //对科目的考生进行分组
                    for (StudentSubject studentSubject : subjectList) {
                        String subjectId = studentSubject.getSubjectId();
                        if (subjectStudents.containsKey(subjectId)) {
                            List<String> studentIds = subjectStudents.get(subjectId);
                            studentIds.add(studentSubject.getStudentId());
                        } else {
                            List<String> studentIds = new ArrayList<>();
                            studentIds.add(studentSubject.getStudentId());
                            subjectStudents.put(subjectId, studentIds);
                        }
                    }
                }
                log.info("## refundComments subjectStudents:{}", FastJsonUtil.getBeanToJson(subjectStudents));
                msg = "14001";
            } else if ("3".equals(map.get("code"))) {
                // 退款失败，跟心退款订单表
                refundComments.setResult((String) map.get("msg"));
                // 退款状态（0:退款申请中 1：退款中,2：退款完成,3：退款失败，）
                refundComments.setRefundStatus(BmRefundStatusEnum.REFUND_FAIL.getRefundStatu());
                orderMapper.updateRefund(refundComments);
                // 更新订单科目中间表
                // 查询退款申请中的科目
                List<String> list = new ArrayList<>();
                List<StudentSubject> subjectList = studentSubjectMapper.getStuSubjectsByOrderIdAndOrderRefundStatus(orderId, BmMidOrderPayRefundStatus.REFUND_APPLY.getRefundStatus());
                if (CollectionUtils.isNotEmpty(subjectList)) {
                    for (StudentSubject studentSubject : subjectList) {
                        list.add(studentSubject.getId());
                    }
                    // 更新 订单报名科目明细表 （退款申请状态，默认：0，申请退款中：1）
                    orderMapper.updateSubjectMidOrderRefundStatus(orderId, list, BmMidOrderPayRefundStatus.REFUND_DEFAULT.getRefundStatus());
                }
                // 更新流水表
                List<String> queryBusinessFlowTypes = new ArrayList<>();
                queryBusinessFlowTypes.add(BmPayBusinessFlowType.REFUND_APPLY.getBusinessType());
                updateBusinessFlow(orderId, listSubjects, queryBusinessFlowTypes, BmPayBusinessFlowType.REFUND_FAIL.getBusinessType());
                // 暂不支持退款
                msg = "31201801";
            } else {
                // 退款失败，跟心退款订单表
                refundComments.setResult((String) map.get("msg"));
                // 退款状态（0:退款申请中 1：退款中,2：退款完成,3：退款失败，）
                refundComments.setRefundStatus(BmRefundStatusEnum.REFUND_FAIL.getRefundStatu());
                orderMapper.updateRefund(refundComments);
                // 更新订单科目中间表
                // 查询退款申请中的科目
                List<String> list = new ArrayList<String>();
                List<StudentSubject> subjectList = studentSubjectMapper.getStuSubjectsByOrderIdAndOrderRefundStatus(orderId, BmMidOrderPayRefundStatus.REFUND_APPLY.getRefundStatus());
                if (CollectionUtils.isNotEmpty(subjectList)) {
                    for (StudentSubject studentSubject : subjectList) {
                        list.add(studentSubject.getId());
                    }
                    // 更新 订单报名科目明细表 （退款申请状态，默认：0，申请退款中：1）
                    orderMapper.updateSubjectMidOrderRefundStatus(orderId, list, BmMidOrderPayRefundStatus.REFUND_DEFAULT.getRefundStatus());
                }
                // 更新流水表
                List<String> queryBusinessFlowTypes = new ArrayList<String>();
                queryBusinessFlowTypes.add(BmPayBusinessFlowType.REFUND_APPLY.getBusinessType());
                updateBusinessFlow(orderId, listSubjects, queryBusinessFlowTypes, BmPayBusinessFlowType.REFUND_FAIL.getBusinessType());
                // 退款失败
                msg = "15047";
            }
        }
        return msg;
    }

    private String getPayRefundNotifyUrl(RefundComments refundComments, Project project, String ip, String port) {
        String officeId = project.getOfficeId();
        StringBuilder notifySb = new StringBuilder();
        String refundNotifyUrl = configManager.getRefundNotifyUrl();
        if (StringUtils.isEmpty(refundNotifyUrl)) {
            notifySb.append("http://");
            notifySb.append(ip);
            notifySb.append(":");
            notifySb.append(port);
            String payProvider = PayProviderType.YIBAO.getType();
            try {
                payProvider = tpsClient.getPayProvider(officeId);
            } catch (Exception e) {
                logger.error("## getPayProvider error", e);
            }
            if (PayProviderType.SHOUYIXIN.getType().equals(payProvider)) {
                notifySb.append("/bm/order/refundNotifyUrl?officeId=");
            }
            if (PayProviderType.YIBAO.getType().equals(payProvider)) {
                notifySb.append("/bm/order/yopRrefundNotifyUrl?officeId=");
            }
            notifySb.append(project.getOfficeId());
            notifySb.append("&id=");
            notifySb.append(refundComments.getId());
        } else {
            notifySb.append(refundNotifyUrl);
            String payProvider = PayProviderType.YIBAO.getType();
            try {
                payProvider = tpsClient.getPayProvider(officeId);
            } catch (Exception e) {
                logger.error("## getPayProvider error", e);
            }
            if (PayProviderType.SHOUYIXIN.getType().equals(payProvider)) {
                notifySb.append("/bm/order/refundNotifyUrl?officeId=");
            }
            if (PayProviderType.YIBAO.getType().equals(payProvider)) {
                notifySb.append("/bm/order/yopRrefundNotifyUrl?officeId=");
            }
            notifySb.append(project.getOfficeId());
            notifySb.append("&id=");
            notifySb.append(refundComments.getId());
        }
        return notifySb.toString();
    }

    private void updateBusinessFlow(String orderId, List<StudentSubject> listSubjects, List<String> queryBusinessFlowTypes, String businessFlowType) {
        if (CollectionUtils.isNotEmpty(listSubjects)) {
            for (StudentSubject studentSubject : listSubjects) {
                // 记录支付成功流水
                String serialNumber = orderMapper.getSerialNumber(orderId);
                OrderBusinessFlow orderBusinessFlow = new OrderBusinessFlow();
                List<OrderBusinessFlow> orderBusinessFlows = orderBusinessFlowMapper.getBusinessFlowByProjectIdAndRegId(orderId, studentSubject.getProjectId(), queryBusinessFlowTypes, null, studentSubject.getId(), null);
                if (CollectionUtils.isNotEmpty(orderBusinessFlows)) {
                    orderBusinessFlow = orderBusinessFlows.get(0);
                    orderBusinessFlow.setBusinessStatus(businessFlowType);
                    orderBusinessFlow.setSerialNumber(serialNumber);
                    orderBusinessFlow.setUpdateDate(LocalDateTime.now());
                    orderBusinessFlowMapper.updateById(orderBusinessFlow);
                }
            }
        }
    }

    private static final String ENCRYPT_KEY = "encryptKey";
    private static final String MERCHANT_ID = "merchantId";

    @Override
    public Map<String, Object> refundNotifyUrl(HttpServletRequest req, String officeId, String id) {
        try {
            String encryptKey = req.getHeader(ENCRYPT_KEY);
            String merchantId = req.getHeader(MERCHANT_ID);
            JSONObject json = FastJsonUtils.convert(req.getInputStream());
            json.put(ENCRYPT_KEY, encryptKey);
            json.put(MERCHANT_ID, merchantId);
            log.info("refundNotify encryptKey:[{}],merchantId:[{}] ", encryptKey, merchantId);
            log.info("refundNotify jsonData:[{}]", json.toString());
            Analysis analysis = new Analysis();
            analysis.setJsonObject(json.toString());
            analysis.setOfficeId(officeId);
            // 第三方解析回调数据
            Map<String, Object> map = (Map<String, Object>) tpsClient.analysis(analysis);
            log.info("refundNotify 解析数据:[{}]", JSON.toJSON(map));
            String amount = (String) map.get("amount");
            String serialNumber = (String) map.get("serialNumber");
            String status = (String) map.get("status");
            // 通过交易流水号查询订单号
            String orderId = orderMapper.getBmOrderId(serialNumber);
            // 通过订单号查询订单详情
            Order order = orderMapper.selectById(orderId);
            // 根据订单查询科目，将科目的缴费状态更新为未缴费
            List<StudentSubject> subjectList = studentSubjectMapper.getStuSubjectsByOrderIdAndOrderRefundStatus(orderId, null);
            if ("SUCCESS".equals(status)) {
                // 更新订单退款表 bm_order_refund
                RefundComments refundComments = new RefundComments();
                refundComments.setId(id);
                //判断是否是部分退款
                Double acturalAmount = Double.parseDouble(amount) / 100;
                // 订单金额大于退款金额
                if (order.getOrderPrice() > acturalAmount) {
                    // 部分退款
                    refundComments.setRefundStatus(BmRefundStatusEnum.REFUND_PART_SUCCESS.getRefundStatu());
                } else {
                    // 退款成功
                    refundComments.setRefundStatus(BmRefundStatusEnum.REFUND_SUCCESS.getRefundStatu());
                }
                refundComments.setUpdateDate(LocalDateTime.now());
                orderMapper.updateRefund(refundComments);

                log.info("## refundNotifyUrl subjectList:{}", FastJsonUtil.getBeanToJson(subjectList));
                for (StudentSubject studentSubject : subjectList) {
                    // 更新科目的缴费状态为退款成功
                    studentSubject.setPay(BmPayStatusEnum.REFUND_SUCEESS.getPayStatus());
                    studentSubject.setUpdateDate(LocalDateTime.now());
                    // 更新报名科目状态
                    studentSubjectMapper.updateById(studentSubject);
                }
                iStudentProjectService.ansycSubjectPayStatus(subjectList);
                // 更新中间表的退款状态为退款成功
                List<String> list = new ArrayList<String>();
                if (CollectionUtils.isNotEmpty(subjectList)) {
                    for (StudentSubject studentSubject : subjectList) {
                        list.add(studentSubject.getId());
                    }
                    // 更新 订单报名科目明细表 （退款申请状态，默认：0，申请退款中：1）
                    orderMapper.updateSubjectMidOrderRefundStatus(orderId, list, BmMidOrderPayRefundStatus.REFUND_SUCCESS.getRefundStatus());
                    // 更新 订单报名科目明细表 （缴费状态，默认：0，申请退款中：1）
                    //orderMapper.updateSubjectMidOrderPayStatus(orderId, list, BmMidOrderPayStatus.PAY_DETAULT.getPayStatus());
                }
                // 更新流水表
                List<String> queryBusinessFlowTypes = new ArrayList<String>();
                queryBusinessFlowTypes.add(BmPayBusinessFlowType.REFUND_PEDDING.getBusinessType());
                updateBusinessFlow(orderId, subjectList, queryBusinessFlowTypes, BmPayBusinessFlowType.REFUND_SUCCESS.getBusinessType());


                Map<String, List<String>> subjectStudents = new HashMap<>();
                if (CollectionUtils.isNotEmpty(subjectList)) {
                    //对科目的考生进行分组
                    for (StudentSubject studentSubject : subjectList) {
                        String subjectId = studentSubject.getSubjectId();
                        if (subjectStudents.containsKey(subjectId)) {
                            List<String> studentIds = subjectStudents.get(subjectId);
                            studentIds.add(studentSubject.getStudentId());
                        } else {
                            List<String> studentIds = new ArrayList<>();
                            studentIds.add(studentSubject.getStudentId());
                            subjectStudents.put(subjectId, studentIds);
                        }
                    }
                }
                log.info("## refundNotifyUrl subjectStudents:{}", FastJsonUtil.getBeanToJson(subjectStudents));
            } else {
                // 更新订单退款表 bm_order_refund
                RefundComments refundComments = new RefundComments();
                refundComments.setId(id);
                refundComments.setRefundStatus(BmRefundStatusEnum.REFUND_FAIL.getRefundStatu());
                refundComments.setUpdateDate(LocalDateTime.now());
                orderMapper.updateRefund(refundComments);
                // 更新中间表的退款状态为退款成功
                List<String> list = new ArrayList<String>();
                if (CollectionUtils.isNotEmpty(subjectList)) {
                    for (StudentSubject studentSubject : subjectList) {
                        list.add(studentSubject.getId());
                    }
                    // 更新 订单报名科目明细表 （退款申请状态，默认：0，申请退款中：1）
                    orderMapper.updateSubjectMidOrderRefundStatus(orderId, list, BmMidOrderPayRefundStatus.REFUND_DEFAULT.getRefundStatus());
                }
                // 更新流水表
                List<String> queryBusinessFlowTypes = new ArrayList<String>();
                queryBusinessFlowTypes.add(BmPayBusinessFlowType.REFUND_PEDDING.getBusinessType());
                updateBusinessFlow(orderId, subjectList, queryBusinessFlowTypes, BmPayBusinessFlowType.REFUND_FAIL.getBusinessType());
            }


        } catch (Exception e) {
            log.info("退款回调失败", e);
        }
        return null;
    }

    @Override
    public IPage<RefundTaskList> refundTaskList(PageParam<RefundTaskList> pageParam, OrderParam param,
                                                String officeName) {
        return orderMapper.refundTaskList(pageParam, param, officeName);
    }

    @Override
    public IPage<Reconciliation> officeReconciliation(PageParam<Reconciliation> pageParam, String officeName) {
        List<String> list = null;
        if (StringUtils.isNotEmpty(officeName)) {
            // 名称模糊查询
            list = officeIdToNameUtil.fuzzySearchByName(officeName);
            if (CollectionUtils.isEmpty(list)) {
                list.add("noofficeId");
            }
        }

        // 需要替换成officeId ; officeName
        IPage<Reconciliation> iPage = orderMapper.officeReconciliation(pageParam, officeName, list);
        officeIdToNameUtil.change(iPage.getRecords(), Reconciliation::getOfficeId, Reconciliation::setOfficeName);
        return iPage;
    }

    @Override
    public List<Project> officeProjectList(String officeId) {
        return orderMapper.projectList(officeId);
    }

    @Override
    public IPage<ReconciliationList> officeReconciliationList(PageParam<ReconciliationList> pageParam, String orderId,
                                                              String projectId, String date, String orderType, String payType, String officeId) {
        Integer dateEnd = 0;
        if (!StringUtils.isEmpty(date)) {
            Integer integer = Integer.parseInt(date);
            dateEnd = integer + 1;
        }
        return orderMapper.officeReconciliationList(pageParam, orderId, projectId, date, orderType, payType, officeId,
                dateEnd + "");
    }

    @Override
    public List<ProjectOrderFlowVo> queryProjectOrderFlowList(String projectId, String regId) {
        List<ProjectOrderFlowVo> paFlowVos = new ArrayList<ProjectOrderFlowVo>();
        // 校验项目是不是存在
        Project projectInfo = projectMapper.selectById(projectId);
        if (null == projectInfo) {
            return paFlowVos;
        }
        // 查询项目考生是不是存在
        StudentProject studentProject = studentProjectMapper.getProjectStudent(projectId, regId);
        if (null == studentProject) {
            return paFlowVos;
        }
        // 获取项目用户的所有流水列表
        List<String> businessStatus = new ArrayList<String>();
        businessStatus.add(BmPayBusinessFlowType.PAY_PEDDING.getBusinessType());
        businessStatus.add(BmPayBusinessFlowType.PAY_SUCCESS.getBusinessType());
        businessStatus.add(BmPayBusinessFlowType.PAY_FAIL.getBusinessType());
        businessStatus.add(BmPayBusinessFlowType.REFUND_PEDDING.getBusinessType());
        businessStatus.add(BmPayBusinessFlowType.REFUND_SUCCESS.getBusinessType());
        businessStatus.add(BmPayBusinessFlowType.REFUND_FAIL.getBusinessType());
        List<OrderBusinessFlow> orderBusinessFlows = orderBusinessFlowMapper.getBusinessFlowByProjectIdAndRegId(null, projectId, businessStatus, regId, null, null);
        Set<String> studentSubjectIds = new HashSet<String>();
        if (CollectionUtils.isNotEmpty(orderBusinessFlows)) {
            for (OrderBusinessFlow orderBusinessFlow : orderBusinessFlows) {
                studentSubjectIds.add(orderBusinessFlow.getBmStudentSubjectId());
            }
        }
        List<String> studentSubjectIdList = new ArrayList<>(studentSubjectIds);
        List<StudentSubject> studentSubjects = studentSubjectMapper.getStudentSubjectByIds(studentSubjectIdList);
        Map<String, String> subjectMap = new HashMap<String, String>();
        if (CollectionUtils.isNotEmpty(studentSubjects)) {
            for (StudentSubject studentSubject : studentSubjects) {
                subjectMap.put(studentSubject.getId(), studentSubject.getSubjectName());
            }
        }
        if (CollectionUtils.isNotEmpty(orderBusinessFlows)) {
            for (OrderBusinessFlow orderBusinessFlow : orderBusinessFlows) {
                ProjectOrderFlowVo projectOrderFlowVo = new ProjectOrderFlowVo();
                projectOrderFlowVo.setSubjectId(orderBusinessFlow.getBmStudentSubjectId());
                projectOrderFlowVo.setSubjectName(subjectMap.get(orderBusinessFlow.getBmStudentSubjectId()));
                String businesStatus = orderBusinessFlow.getBusinessStatus();
                String payDesc = BmPayBusinessFlowType.getPayDesc(businesStatus);
                projectOrderFlowVo.setFlowTypeDesc(payDesc);
                projectOrderFlowVo.setOrderFlowPrice(String.valueOf(orderBusinessFlow.getOrderPrice()));
                projectOrderFlowVo.setCreateTime(DateUtils.dateToString(DateUtils.asDate(orderBusinessFlow.getUpdateDate()), DateUtils.YYYY_MM_DD_HH_MM_SS));
                projectOrderFlowVo.setBusinessType(orderBusinessFlow.getBusinessStatus());
                projectOrderFlowVo.setBusinessTypeDesc(BmPayBusinessFlowType.getMsg(orderBusinessFlow.getBusinessStatus()));
                paFlowVos.add(projectOrderFlowVo);
            }
        }
        return paFlowVos;
    }


    @Override
    public Map<String, Object> yopRrefundNotifyUrl(String customerIdentification, String orderJson, String id) throws Exception {
        if (StringUtils.isEmpty(orderJson) || StringUtils.isEmpty(customerIdentification)) {
            throw new Exception("数据签名验证失败");
        }
        RefundQueryQueryRefundResponseDTOResult refundQueryQueryRefundResponseDTOResult = JsonUtil.fromJson(orderJson, RefundQueryQueryRefundResponseDTOResult.class);
        // 订单号
        String bmOrderId = refundQueryQueryRefundResponseDTOResult.getOrderId();
        if (StringUtils.isEmpty(bmOrderId)) {
            log.error("## 易宝退款回调参数订单号缺失:[{}]", bmOrderId);
            throw new Exception("易宝支付回调参数订单号缺失");
        }

        BigDecimal amount = refundQueryQueryRefundResponseDTOResult.getRefundAmount();
        String serialNumber = refundQueryQueryRefundResponseDTOResult.getUniqueOrderNo();
        log.info("# yopRrefundNotifyUrl serialNumber:[{}]", serialNumber);
        if (StrUtil.isEmptyIfStr(serialNumber)) {
            log.error("## 易宝退款回调参数序列化订单号缺失serialNumber:[{}]", serialNumber);
            throw new Exception("易宝支付回调参数退款流水号缺失");
        }
        String status = refundQueryQueryRefundResponseDTOResult.getStatus();
        // 通过交易流水号查询订单号
        String orderId = orderMapper.getBmOrderId(serialNumber);
        if (StrUtil.isEmptyIfStr(orderId)) {
            log.error("## 易宝退款回调参数序列化订单号查询订单ID为空orderId:[{}]", orderId);
            throw new Exception("易宝支付回调参数退款流水号查询订单ID为空");
        }
        if (!bmOrderId.equals(orderId)) {
            log.error("## 易宝退款回调参数退款流水号查询订单匹配不上,bmOrderId:{}, orderId:{}", bmOrderId, orderId);
            throw new Exception("易宝支付回调参数退款流水号查询订单匹配不上");
        }
        // 通过订单号查询订单详情
        Order order = orderMapper.selectById(orderId);
        if (null == order) {
            log.error("## 易宝退款回调参数退款流水号查询订单实体为空orderId:{}", orderId);
            throw new Exception("易宝支付回调参数退款流水号查询订单为空");
        }
        List<StudentSubject> subjectList = getOrderRefundSubjects(orderId, serialNumber);

        if ("SUCCESS".equals(status)) {
            // 更新订单退款表 bm_order_refund
            RefundComments refundComments = new RefundComments();
            refundComments.setId(id);
            //判断是否是部分退款
            Double acturalAmount = amount.doubleValue() / 100;
            // 订单金额大于退款金额
            if (order.getOrderPrice() > acturalAmount) {
                // 部分退款
                refundComments.setRefundStatus(BmRefundStatusEnum.REFUND_PART_SUCCESS.getRefundStatu());
            } else {
                // 退款成功
                refundComments.setRefundStatus(BmRefundStatusEnum.REFUND_SUCCESS.getRefundStatu());
            }
            refundComments.setUpdateDate(LocalDateTime.now());
            orderMapper.updateRefund(refundComments);

            log.info("## 易宝退款回调考生报考科目列表详情:{}", FastJsonUtil.getBeanToJson(subjectList));
            for (StudentSubject studentSubject : subjectList) {
                // 更新科目的缴费状态为退款成功
                studentSubject.setPay(BmPayStatusEnum.REFUND_SUCEESS.getPayStatus());
                studentSubject.setUpdateDate(LocalDateTime.now());
                // 更新报名科目状态
                studentSubjectMapper.updateById(studentSubject);
            }
            iStudentProjectService.ansycSubjectPayStatus(subjectList);
            // 更新中间表的退款状态为退款成功
            List<String> list = new ArrayList<String>();
            if (CollectionUtils.isNotEmpty(subjectList)) {
                for (StudentSubject studentSubject : subjectList) {
                    list.add(studentSubject.getId());
                }
                // 更新 订单报名科目明细表 （退款申请状态，默认：0，申请退款中：1）
                orderMapper.updateSubjectMidOrderRefundStatus(orderId, list, BmMidOrderPayRefundStatus.REFUND_SUCCESS.getRefundStatus());
                // 更新 订单报名科目明细表 （缴费状态，默认：0，申请退款中：1）
                //orderMapper.updateSubjectMidOrderPayStatus(orderId, list, BmMidOrderPayStatus.PAY_DETAULT.getPayStatus());
            }

            // 如果订单的所有的科目都退款完成，则需要修改退款订单的状态的退款完成
            List<StudentSubjectMidOrderDetails> subjectMidOrderDetails = studentSubjectMidOrderDetailsMapper.queryUnRefundFinishSubjects(orderId, BmMidOrderPayRefundStatus.REFUND_SUCCESS.getRefundStatus());
            log.info("## 易宝退款回调查询考生报考订单科目列表详情:{}", FastJsonUtil.getBeanToJson(subjectMidOrderDetails));
            // 没有查到为退款完成的，说明全部退款完成
            if (CollUtil.isEmpty(subjectMidOrderDetails)) {
                // 修改退款订单状态为退款完成
                orderMapper.updateRefundStatus(orderId, null, BmRefundStatusEnum.REFUND_SUCCESS.getRefundStatu());
            }
            // 更新流水表
            List<String> queryBusinessFlowTypes = new ArrayList<String>();
            queryBusinessFlowTypes.add(BmPayBusinessFlowType.REFUND_PEDDING.getBusinessType());
            updateBusinessFlow(orderId, subjectList, queryBusinessFlowTypes, BmPayBusinessFlowType.REFUND_SUCCESS.getBusinessType());
        } else {
            // 更新订单退款表 bm_order_refund
            RefundComments refundComments = new RefundComments();
            refundComments.setId(id);
            refundComments.setRefundStatus(BmRefundStatusEnum.REFUND_FAIL.getRefundStatu());
            refundComments.setUpdateDate(LocalDateTime.now());
            orderMapper.updateRefund(refundComments);
            // 更新中间表的退款状态为退款成功
            List<String> list = new ArrayList<String>();
            if (CollectionUtils.isNotEmpty(subjectList)) {
                for (StudentSubject studentSubject : subjectList) {
                    list.add(studentSubject.getId());
                }
                // 更新 订单报名科目明细表 （退款申请状态，默认：0，申请退款中：1）
                orderMapper.updateSubjectMidOrderRefundStatus(orderId, list, BmMidOrderPayRefundStatus.REFUND_DEFAULT.getRefundStatus());
            }
            // 更新流水表
            List<String> queryBusinessFlowTypes = new ArrayList<String>();
            queryBusinessFlowTypes.add(BmPayBusinessFlowType.REFUND_PEDDING.getBusinessType());
            updateBusinessFlow(orderId, subjectList, queryBusinessFlowTypes, BmPayBusinessFlowType.REFUND_FAIL.getBusinessType());
        }
        return null;
    }

    private List<StudentSubject> getOrderRefundSubjects(String orderId, String serialNumber) {
        List<Integer> refundStatus = new ArrayList<>();
        refundStatus.add(BmRefundStatusEnum.REFUND_APPLY.getRefundStatu());
        refundStatus.add(BmRefundStatusEnum.REFUND_RUNNING.getRefundStatu());
        refundStatus.add(BmRefundStatusEnum.REFUND_FAIL.getRefundStatu());
        RefundInfo refundInfo = orderMapper.getRefundSubjectListByProjectIdAndSerialNumber(orderId, serialNumber, refundStatus);
        List<String> subjectIds = Arrays.asList(refundInfo.getRefundStudentSubjectid().split(","));
        // 查询退款申请中的科目
        List<StudentSubject> subjectList = studentSubjectMapper.getStuSubjectsByOrderIdAndSubjectIds(orderId, subjectIds);
        return subjectList;
    }

    @Override
    public String analysisYopNotifyStr(String response, String officeId) {
        try {
            log.info("## analysisYopNotifyStr params:{}, officeId:{}", response, officeId);
            if (StringUtils.isEmpty(officeId)) {
                officeId = "1";
            }
            String result = tpsClient.analysisYopNotifyStr(response, officeId);
            log.info("## analysisYopNotifyStr result:{}", result);
            return result;
        } catch (Exception e) {
            log.error("## analysisYopNotifyStr error", e);
        }
        return null;
    }

    /**
     * 根据项目Id和用户Id以及支付状态获取订单列表
     *
     * @see com.hyt.it.ogt.kq.service.bm.service.IPayOrderService#getOrderListsByProIdAndRegId(java.lang.String, java.lang.String, java.util.List)
     **/
    @Override
    public List<Order> getOrderListsByProIdAndRegId(String projectId, String regId, List<String> payStatus) {
        LambdaQueryWrapper<Order> wrapper = new LambdaQueryWrapper<>();
        if (CharSequenceUtil.isNotBlank(projectId)) {
            wrapper.eq(Order::getBmProjectId, projectId);
        }
        if (CharSequenceUtil.isNotBlank(regId)) {
            wrapper.eq(Order::getRegId, regId);
        }
        if (CollUtil.isNotEmpty(payStatus)) {
            wrapper.in(Order::getPayStatus, payStatus);
        }
        wrapper.eq(Order::getDelFlag, DelFlagEnum.NORMAL.getCode());
        return list(wrapper);
    }

    /**
     * 南昌非税系统获取私钥
     * @see com.hyt.it.ogt.kq.service.bm.service.IPayOrderService#getNcNonTaxPayPrivateKey(java.lang.String)
     **/
    @Override
    public String getNcNonTaxPayPrivateKey(String officeId) throws Exception {
        return tpsClient.getNcNonTaxPayPrivateKey(officeId);
    }
}
